﻿#include "cameramanager.h"
#include <QMap>
#include <QVector>
#include <QFile>
#include <QTime>
#include <QDataStream>
#include <QDebug>
#include "Infra/Error.h"
#include "CameraAttribute.h"
#include "GenICam/GigE/GigECamera.h"
#include "GenICam/GigE/GigEInterface.h"

#define DEFAULT_SHOW_RATE (15)

using namespace Dahua;
CameraManager::CameraManager() :_systemIns(GenICam::CSystem::getInstance())
{
    Init();
}

void CameraManager::Init() {
	_isGrabbing = false;
	_bRunning = false;
    _cameraVec.clear();
    if (!_systemIns.discovery(_cameraVec))
    {
        //MessageBox("Discovery Cameras Failed.", "", 0);
    }
    else
    {
        initTree(_cameraVec);
        //_callBackFunc = callBack;
    }
}

QString CameraManager::GetSerialNumWithInterfaceName(QString interfaceName)
{
	int idx = 0;
	CameraVec::iterator it = _cameraVec.begin();
	for (; it != _cameraVec.end(); ++it, ++idx)
	{
		GenICam::ICameraPtr& camPtr = (*it);
		if (camPtr == nullptr)
		{
			continue;
		}	
		std::string str = camPtr->getName();
		if (str.length()==0)
		{
			str = camPtr->getInterfaceName();
		}
		//std::string str = camPtr->getInterfaceName();
		QString in = QString::fromLocal8Bit(QByteArray::fromRawData(str.c_str(), str.size()));

		if (in.compare(interfaceName, Qt::CaseInsensitive) == 0)
		{
			return camPtr->getSerialNumber();
		}
	}
	return "";
}

QString CameraManager::GetInterfaceNameWithSerialNum(QString sn)
{
	int idx = 0;
	CameraVec::iterator it = _cameraVec.begin();
	for (; it != _cameraVec.end(); ++it, ++idx)
	{
		GenICam::ICameraPtr& camPtr = (*it);
		if (camPtr == nullptr)
		{
			continue;
		}
		std::string str1 = camPtr->getSerialNumber();
		QString in = QString::fromLocal8Bit(QByteArray::fromRawData(str1.c_str(), str1.size()));

		if (in.compare(sn, Qt::CaseInsensitive) == 0)
		{
			std::string str = camPtr->getName();
			if (str.length() == 0)
			{
				str = camPtr->getInterfaceName();
			}
			return QString::fromLocal8Bit(QByteArray::fromRawData(str.c_str(), str.size()));
		}
	}
	return "";
}

bool CameraManager::SelectCameraWithSerialNum(QString sn)
{
	CameraVec::iterator it = _cameraVec.begin();
	int idx = 0;
	for (; it != _cameraVec.end(); ++it, ++idx)
	{
		Dahua::GenICam::ICameraPtr& camPtr = (*it);
		if (camPtr == nullptr)
		{
			continue;
		}
		//QString sn1 = QString::fromStdString(camPtr->getSerialNumber());
		std::string str = camPtr->getSerialNumber();
		QString sn1 = QString::fromLocal8Bit(QByteArray::fromRawData(str.c_str(), str.size()));
		if (sn.compare(sn1, Qt::CaseInsensitive) == 0)
		{
			_currentCamera = camPtr;
			return true;
		}

	}

	return false;
}

// 初始化树形结构
void CameraManager::initTree(CameraVec& cameraPtrVec)
{

    int idx = 0;
    CameraVec::iterator it = cameraPtrVec.begin();
    for (; it != cameraPtrVec.end(); ++it, ++idx)
    {
        GenICam::ICameraPtr& camPtr = (*it);
        if (camPtr == nullptr)
        {
            continue;
        }

		Dahua::GenICam::IGigEInterfacePtr interfacePtr = Dahua::GenICam::IGigEInterface::getInstance(camPtr);
		if (NULL != interfacePtr)
		{
			Infra::CString interfaceIpAddr, interfaceMask, interfaceGateway;
			interfaceIpAddr = interfacePtr->getIpAddress();
			interfaceMask = interfacePtr->getSubnetMask();
			interfaceGateway = interfacePtr->getGateway();
			//qDebug() << interfaceIpAddr.c_str() << interfaceMask.c_str() << interfaceGateway.c_str();
			QString s = interfaceIpAddr.c_str();
			Dahua::GenICam::IGigECameraPtr cameraPtr = Dahua::GenICam::IGigECamera::getInstance(camPtr);
			QString s1 = cameraPtr->getIpAddress().c_str();
			QStringList list1 = s1.split(".");
			QStringList list = s.split(".");
			int equalNum = 0;
			if (list.count() >= 3 && list1.count() >= 3)
			{
				for (int i = 0; i < 3; i++)
				{
					int n = list[i].toInt();
					int n1 = list1[i].toInt();
					if (n == n1)
					{
						equalNum++;
					}
				}
			}

			if (equalNum != 3)
			{
				if (list.count() == 4)
				{
					QString num = list[3];
					int n = num.toInt() + 1 + idx;
					if (n > 254)
					{
						n = 1;
					}

					list[3] = QString::number(n);
				}
				QString ip = list[0] + "." + list[1] + "." + list[2] + "." + list[3];

				if (!cameraPtr->forceIpAddress(ip.toUtf8(), interfaceMask.c_str(), interfaceGateway.c_str()))
				{

				}
			}
		}
		

      //  std::string intfaceName = camPtr->getInterfaceName();
		std::string intfaceName = camPtr->getName();
		if (intfaceName.length() == 0)
		{
			intfaceName = camPtr->getInterfaceName();
		}
        CameraManager::InterfaceMap::iterator it = _interfaces.find(intfaceName);
        if (it != _interfaces.end())
        {
            CameraInfo info = { camPtr->getKey(), camPtr->getSerialNumber(), idx };
            it.value().push_back(info);
           // it->second.push_back(info);
        }
        else
        {
            std::vector<CameraInfo> cameraVec;
            CameraInfo info = { camPtr->getKey(), camPtr->getSerialNumber(), idx };
            cameraVec.push_back(info);
            _interfaces.insert(intfaceName, cameraVec);
         //   (void)interfaces.insert(std::make_pair(intfaceName, cameraVec));
        }
    }
    if (_cameraVec.empty())
    {
        return;
    }
    GenICam::ICameraPtr& camera = _cameraVec[0];

    assert(NULL != camera);

    //// 非GIGE不需要修改IP
    if (GenICam::ICamera::typeGige != camera->getType())
    {

    }

    _currentCamera = camera;
}


void CameraManager::OnConnectEvent(const Dahua::GenICam::SConnectArg& arg)
{
  //  CString csLog;
    if (arg.m_event == Dahua::GenICam::SConnectArg::offLine)
    {
		_bRunning = false;
     //   _disconnectCB();
        emit disconnectEvent();
        StopStreamGrabbing();
        Dahua::GenICam::IEventSubscribePtr evtSubscribePtr =
            Dahua::GenICam::CSystem::getInstance().createEventSubscribe(_currentCamera);
        assert(evtSubscribePtr);

        if (!evtSubscribePtr->unsubscribeConnectArgs(Dahua::GenICam::ConnectArgProc(&CameraManager::OnConnectEvent, this)))
        {
            ;
        }
    }
    else 
	{
    }
}


BOOL CameraManager::Connect()
{
    if (_currentCamera == nullptr)
	{
        emit connectedEvent(2, m_width, m_height);
		return FALSE;
	}
    BOOL bRet = _currentCamera->connect();
  //  _disconnectCB = cb;
    if (bRet)
    {
        
        Dahua::GenICam::IEventSubscribePtr evtSubscribePtr =
            Dahua::GenICam::CSystem::getInstance().createEventSubscribe(_currentCamera);
        assert(evtSubscribePtr);
		_bRunning = true;
        if (!evtSubscribePtr->subscribeConnectArgs(Dahua::GenICam::ConnectArgProc(&CameraManager::OnConnectEvent, this)))
        {
            //MessageBox(_T("添加断线回调失败"), _T(""), 0);
        }

		_stream = GenICam::CSystem::getInstance().createStreamSource(_currentCamera);
		if (nullptr == _stream)
		{
			//MessageBox("Get Stream Failed.", "", 0);
		}
		UpdateDefaultCfg();
		emit connectedEvent(1, m_width, m_height);
    }
	else 
	{
		int err = Dahua::Infra::getLastError();
		const char *msg = Dahua::Infra::getErrMsg(err);
		qDebug() << msg;
		emit connectedEvent(err, m_width, m_height);
	}
    
    return bRet;
}

bool CameraManager::SetCameraLive(bool bLive)
{
	Dahua::GenICam::IAcquisitionControlPtr sptrAcquisitionCtl = GenICam::CSystem::getInstance().createAcquisitionControl(_currentCamera);
	if (NULL == sptrAcquisitionCtl.get())
	{
		qDebug() << ("create AcquisitionControl object fail.\n");
		//emit connectStateEvent(CONNECT_FAIL);
		return FALSE;
	}

	//设置触发源为软触发
	Dahua::GenICam::CEnumNode enumNode = sptrAcquisitionCtl->triggerSource();
	Infra::CString cs;
	enumNode.getValueSymbol(cs);
	//qDebug() << "triggerSource" << cs.c_str();
	bool bRet = enumNode.setValueBySymbol("Software");
	if (bRet != true)
	{
		printf("set trigger source fail.\n");
		return false;
	}

	//设置触发器
	enumNode = sptrAcquisitionCtl->triggerSelector();
	bRet = enumNode.setValueBySymbol("FrameStart");
	if (bRet != true)
	{
		printf("set trigger selector fail.\n");
		return false;
	}

	////设置触发模式
	enumNode = sptrAcquisitionCtl->triggerMode();
	////Infra::CString cs;
	//enumNode.getValueSymbol(cs);
	//qDebug() << "triggerMode" << cs.c_str();
	if (bLive)
	{
		bRet = enumNode.setValueBySymbol("Off");
		_stream->attachGrabbing(GenICam::IStreamSource::Proc(&CameraManager::onGetFrame, this));
	}
	else
	{
		bRet = enumNode.setValueBySymbol("On");
		_stream->detachGrabbing(GenICam::IStreamSource::Proc(&CameraManager::onGetFrame, this));
	}
	qDebug() << __FUNCTION__<<"live:" << bLive;
	if (bRet != true)
	{
		printf("set trigger mode fail.\n");
		return false;
	}
	return true;
}

void CameraManager::UpdateDefaultCfg()
{
	std::vector< XmlCfgItem > cfgItemVec;

	QString path = QString("%1/Config/Camera.cfg").arg(QCoreApplication::applicationDirPath());
	QFile file(path);

	if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {  // 以只写模式打开文件
		QXmlStreamReader reader(&file);

		// 解析 XML，直到结束
		while (!reader.atEnd()) {

			// 读取下一个元素
			QXmlStreamReader::TokenType nType = reader.readNext();

			switch (nType) {
				//                case QXmlStreamReader::StartDocument: {  // 开始文档
				//                 //   qDebug() << "********** 开始文档（XML 声明） ********** ";
				//                    // XML 声明
				//                    QString strVersion = reader.documentVersion().toString();
				//                    QString strEncoding = reader.documentEncoding().toString();
				//                    bool bAlone = reader.isStandaloneDocument();
				//                 //   qDebug() << QString("版本：%1  编码：%2  Standalone：%3").arg(strVersion).arg(strEncoding).arg(bAlone) << "\r\n";
				//                    break;
				//                }

			case QXmlStreamReader::StartElement: {  // 开始元素
				QString strElementName = reader.name().toString();
				if (QString::compare(strElementName, "Item") == 0) {  // 根元素
				 //   qDebug() << QString("********** 开始元素<Item> ********** ");
					QXmlStreamAttributes attributes = reader.attributes();
					QString name, value;
					if (attributes.hasAttribute("name")) {
						name = attributes.value("name").toString();
					}
					if (attributes.hasAttribute("value")) {
						value = attributes.value("value").toString();
					}
					//  qDebug() << name <<": "<<value;
					XmlCfgItem item;
					item.name = name.toStdString();
					item.value = value.toStdString();
					cfgItemVec.push_back(item);
				}
				break;
			}

			default:
				break;
			}
		}

		if (reader.hasError()) {  // 解析出错
			qDebug() << QString("错误信息：%1  行号：%2  列号：%3  字符位移：%4").arg(reader.errorString()).arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.characterOffset());
		}

		file.close();  // 关闭文件
	}

	{
		AttrCtrlBasePtr c = AttrCtrlBasePtr(new ExposureTimeAttr(nullptr, nullptr));
		c->init(_currentCamera);
		c->readCfg(_currentCamera, cfgItemVec);
	}
	{
		AttrCtrlBasePtr c = AttrCtrlBasePtr(new GammaAttr(nullptr, nullptr));
		c->init(_currentCamera);
		c->readCfg(_currentCamera, cfgItemVec);
	}
	{
		AttrCtrlBasePtr c = AttrCtrlBasePtr(new BrightnessAttr(nullptr, nullptr));
		c->init(_currentCamera);
		c->readCfg(_currentCamera, cfgItemVec);
	}
	{
		AttrCtrlBasePtr c = AttrCtrlBasePtr(new DigitalShiftAttr(nullptr, nullptr));
		c->init(_currentCamera);
		c->readCfg(_currentCamera, cfgItemVec);
	}
	{
		AttrCtrlBasePtr c = AttrCtrlBasePtr(new ContrastAttr(nullptr, nullptr));
		c->init(_currentCamera);
		c->readCfg(_currentCamera, cfgItemVec);
	}
	{
		AttrCtrlBasePtr c = AttrCtrlBasePtr(new ContrastThresholdAttr(nullptr, nullptr));
		c->init(_currentCamera);
		c->readCfg(_currentCamera, cfgItemVec);
	}

	Dahua::GenICam::IGigECameraPtr cameraPtr = Dahua::GenICam::IGigECamera::getInstance(_currentCamera);
	if (cameraPtr)
	{
		{
			Dahua::GenICam::CBoolNode boolNode(_currentCamera, "GevCurrentIPConfigurationPersistentIP");
			boolNode.setValue(true);
		}
		{
			Infra::CString ip1 = cameraPtr->getIpAddress();
			Dahua::GenICam::CStringNode strNode(_currentCamera, "GevPersistentIPAddress");
			strNode.setValue(ip1);
		}
		{
			Dahua::GenICam::CStringNode strNode(_currentCamera, "GevPersistentSubnetMask");
			Infra::CString ip2 = cameraPtr->getSubnetMask();
			strNode.setValue(ip2);
		}
		{
			Dahua::GenICam::CStringNode strNode(_currentCamera, "GevPersistentDefaultGateway");
			Infra::CString ip3 = cameraPtr->getGateway();
			strNode.setValue(ip3);
		}
	}
	
	{
		Dahua::GenICam::CEnumNode enumNode(_currentCamera, "PixelFormat");
		Infra::TVector<Infra::CString> ff = enumNode.getEnumSymbolList();
		Infra::CString vvv;
		enumNode.getValueSymbol(vvv);
		QString pf = vvv.c_str();
		int k = pf.toUpper().indexOf("MONO");
		m_bIsColorCamera = k == -1;
	}
	
	{
		Dahua::GenICam::CIntNode intNode(_currentCamera, "Width");
		intNode.getValue(m_width);
	}
	{
		Dahua::GenICam::CIntNode intNode(_currentCamera, "Height");
		intNode.getValue(m_height);
	}

	{
		Dahua::GenICam::IAcquisitionControlPtr sptrAcquisitionCtl = GenICam::CSystem::getInstance().createAcquisitionControl(_currentCamera);
		if (NULL == sptrAcquisitionCtl.get())
		{
			qDebug() << ("create AcquisitionControl object fail.\n");
			//emit connectStateEvent(CONNECT_FAIL);
			return;
		}
		Dahua::GenICam::CEnumNode enumNode = sptrAcquisitionCtl->acquisitionMode();
		enumNode.setValueBySymbol("Continuous");
	}
}

bool CameraManager::isTimeToDisplay()
{
	Infra::CGuard guard(m_mxTime);
	m_dDisplayInterval = 1000 * 1000 * 1000.0 / DEFAULT_SHOW_RATE;
	// 不显示
	if (m_dDisplayInterval <= 0)
	{
		return false;
	}

	// 第一帧必须显示
	if (m_nFirstFrameTime == 0 || m_nLastFrameTime == 0)
	{
		m_nFirstFrameTime = Infra::CTime::getCurrentMicroSecond() * 1000;;
		m_nLastFrameTime = m_nFirstFrameTime;

		//TRACE("set m_nFirstFrameTime: %I64d\n", m_nFirstFrameTime);
		return true;
	}
	//Infra::CGuard guard(m_mxTime);
	
	uint64_t nCurTimeTmp = Infra::CTime::getCurrentMicroSecond() * 1000;
	uint64_t nAcquisitionInterval = nCurTimeTmp - m_nLastFrameTime;
	if (nAcquisitionInterval > m_dDisplayInterval)
	{
		m_nLastFrameTime = nCurTimeTmp;
		return true;
	}

	// 当前帧相对于第一帧的时间间隔

	uint64_t nPre = (m_nLastFrameTime - m_nFirstFrameTime) % m_dDisplayInterval;
	if (nPre + nAcquisitionInterval > m_dDisplayInterval)
	{
		m_nLastFrameTime = nCurTimeTmp;
		return true;
	}

	return false;
}

void CameraManager::onGetFrame(const Dahua::GenICam::CFrame & frame)
{
	if (!this->isTimeToDisplay())
	{
		return;
	}
	
	FrameBufferSPtr pDisplayFrame;
	if (ConvertToBGR24(frame, pDisplayFrame))
	{
		_currentFrame = pDisplayFrame;
		int w = pDisplayFrame->Width();
		int h = pDisplayFrame->Height();
		HalconCpp::HImage m_latestImage;
		if (m_bIsColorCamera)
		{
			GenImageInterleaved(&m_latestImage, reinterpret_cast<Hlong>(pDisplayFrame->bufPtr()), "bgr", w, h, 0, "byte", 0, 0, 0, 0, 8, 0);
		}
		else
		{
			GenImage1(&m_latestImage, "byte", w, h, reinterpret_cast<Hlong>(pDisplayFrame->bufPtr()));
		}
		if (_cb)
		{	
			//qDebug() << __FUNCTION__ << "cb";
			_cb(w, h, m_latestImage, _wnd);
		}
	}
}

// 开始拉流
BOOL CameraManager::StartStreamGrabbing()
{
    _stream->attachGrabbing( GenICam::IStreamSource::Proc(&CameraManager::onGetFrame, this));
    m_bStopGrabbing = false;

    _render.setHandle(_wnd);
    // 显示打开
    if (!_render.isOpen())
    {
        _render.open();
        if (!_render.isOpen())
        {
            return false;
        }
    }


    if (!_stream->startGrabbing())
    {
		qDebug() << "startGrabbing false";
        return false;
    }


    _isGrabbing = true;

    return true;
}

// 停止拉流
BOOL CameraManager::StopStreamGrabbing()
{
    //_bRunning = false;

    m_bStopGrabbing = true;

    if (_stream == nullptr)
        return true;

    _isGrabbing = false;


    _stream->detachGrabbing(GenICam::IStreamSource::Proc(&CameraManager::onGetFrame, this));


    if (!_stream->stopGrabbing())
    {
        return false;
    }

    //{
    //    Infra::CGuard guard(m_mutexQue);
    //	m_displayQue.clear();
    //}

    return true;
}
void CameraManager::GrabImage(callback cb, HWND wnd)
{
    _cb = cb;
    _wnd = wnd;
	StartStreamGrabbing();
}


void CameraManager::SaveImage(QString path)
{
    //获取转换后的数据
    FrameBufferSPtr	pDisplayFrame = _currentFrame;
    if (!pDisplayFrame)
    {
       // TRACE("No data can been saved.\n");
        return;
    }

    static int i = 0;
    int dataSize = 0;

    unsigned int uRgbQuadLen = 0;                   //调色板，只有8bit以下才需要
    BITMAPFILEHEADER bmpFileHeader;
    BITMAPINFOHEADER bmpInfoHeader;

    // 设置BMP文件头
    bmpFileHeader.bfType = 0x4D42;        // 文件头类型 'BM'(42 4D)
    bmpFileHeader.bfSize = sizeof(bmpFileHeader) + sizeof(bmpInfoHeader) + pDisplayFrame->Width() * pDisplayFrame->Height() * 3; //文件大小
    bmpFileHeader.bfReserved1 = 0;             //保留字
    bmpFileHeader.bfReserved2 = 0;             //保留字

                                               // 设置BMP信息头
    bmpInfoHeader.biSize = 40;							//信息头所占字节数
    bmpInfoHeader.biWidth = pDisplayFrame->Width();		//位图宽度
    bmpInfoHeader.biHeight = pDisplayFrame->Height();	//位图高度
    bmpInfoHeader.biPlanes = 1;							//位图平面数

                                                        /* 转码 */
    if (pDisplayFrame->PixelFormat() == Dahua::GenICam::gvspPixelMono8)
    {
        dataSize = pDisplayFrame->DataSize();
        bmpInfoHeader.biHeight = -pDisplayFrame->Height();
        bmpInfoHeader.biBitCount = 8;
        uRgbQuadLen = sizeof(RGBQUAD) * 256;
        bmpFileHeader.bfSize = sizeof(bmpFileHeader) + sizeof(bmpInfoHeader) + uRgbQuadLen + pDisplayFrame->Width() * pDisplayFrame->Height();
    }
    else
    {
        dataSize = pDisplayFrame->Width() * pDisplayFrame->Height() * 3;
        bmpInfoHeader.biHeight = -pDisplayFrame->Height();	//rgb数据保存为bmp，上下会颠倒，需要设置height为负值
        bmpInfoHeader.biBitCount = 24;						//像素位数
    }

    bmpFileHeader.bfOffBits = 54 + uRgbQuadLen;     //位图像素数据的起始位置

    bmpInfoHeader.biCompression = 0;             //压缩类型，0 即不压缩
    bmpInfoHeader.biSizeImage = 0;
    bmpInfoHeader.biXPelsPerMeter = 0;
    bmpInfoHeader.biYPelsPerMeter = 0;
    bmpInfoHeader.biClrUsed = 0;
    bmpInfoHeader.biClrImportant = 0;

  //  DWORD dwWrite = 0;
  /*  DWORD length = 0;
    uint8_t *buf = new uint8_t[dataSize];
    memcpy(buf + length, &bmpFileHeader, sizeof(BITMAPFILEHEADER));
    length += sizeof(BITMAPFILEHEADER);
    memcpy(buf+length, &bmpInfoHeader, sizeof(BITMAPINFOHEADER));
    length += sizeof(BITMAPFILEHEADER);*/

//	QString name = QString("%1__.bmp").arg(QTime::currentTime().toString("hh_mm_ss"));


   // qDebug()<<name;
    QFile file(path);
    file.open(QIODevice::WriteOnly);
    QDataStream out(&file);
	int c1 = sizeof(BITMAPFILEHEADER);
	int c2 = sizeof(BITMAPINFOHEADER);
    out.writeRawData((char *)&bmpFileHeader, c1);
    out.writeRawData((char *)&(bmpInfoHeader), c2);



//    WriteFile(hFile, &bmpFileHeader, sizeof(BITMAPFILEHEADER), &dwWrite, NULL);
//    WriteFile(hFile, &(bmpInfoHeader), sizeof(BITMAPINFOHEADER), &dwWrite, NULL);
	RGBQUAD g_rgbQuad[256] = { 0 };
    if (pDisplayFrame->PixelFormat() == Dahua::GenICam::gvspPixelMono8)
    {
        static bool sbRgbQuadInit = false;
        if (!sbRgbQuadInit)
        {
            for (int i = 0; i < 256; ++i)
            {
                g_rgbQuad[i].rgbBlue = g_rgbQuad[i].rgbGreen = g_rgbQuad[i].rgbRed = i;
            }
            sbRgbQuadInit = true;
        }
     //   memcpy(buf + length, g_rgbQuad, uRgbQuadLen);
     //   length += uRgbQuadLen;
       // WriteFile(hFile, g_rgbQuad, uRgbQuadLen, &dwWrite, NULL);
        out.writeRawData((char *)g_rgbQuad, uRgbQuadLen);
    }

   // WriteFile(hFile, (BYTE*)(pDisplayFrame->bufPtr()), dataSize, &dwWrite, NULL);
	out.writeRawData((char *)pDisplayFrame->bufPtr(), dataSize);
   // memcpy(buf + length, (BYTE*)(pDisplayFrame->bufPtr()), dataSize);
   // length += uRgbQuadLen;
	file.flush();
  //  delete buf;
    return;
 //   CloseHandle(hFile);
}



BOOL CameraManager::Disconnect()
{
    StopStreamGrabbing();

    if (nullptr != _currentCamera && !_currentCamera->disConnect())
    {
        //MessageBox(L"Disconnect Failed.", L"", 0);
    }

    Dahua::GenICam::IEventSubscribePtr evtSubscribePtr =
        Dahua::GenICam::CSystem::getInstance().createEventSubscribe(_currentCamera);
    assert(evtSubscribePtr);

    if (!evtSubscribePtr->unsubscribeConnectArgs(Dahua::GenICam::ConnectArgProc(&CameraManager::OnConnectEvent, this)))
    {
        //	MessageBox(_T(" 删除断线回调失败"), _T(""), 0);
    }
    emit disconnectEvent();
	_bRunning = false;
    return true;
}

HalconCpp::HImage CameraManager::GetLatestImage()
{
	HalconCpp::HImage img;
	Dahua::GenICam::CFrame frame;
	bool b = _stream->getFrame(frame, 800);
	if (!b)
	{
		if (ERROR_FUNCTION_HAS_NOT_BEEN_ATTACHED == Dahua::Infra::getLastError())
		{
			SoftwareTrigger();
			b = _stream->getFrame(frame, 800);
		}
	}
	if (b)
	{
		FrameBufferSPtr pDisplayFrame;
		if (ConvertToBGR24(frame, pDisplayFrame))
		{
			_currentFrame = pDisplayFrame;
			int w = pDisplayFrame->Width();
			int h = pDisplayFrame->Height();

			if (m_bIsColorCamera)
			{
				GenImageInterleaved(&img, reinterpret_cast<Hlong>(pDisplayFrame->bufPtr()), "bgr", w, h, 0, "byte", 0, 0, 0, 0, 8, 0);
			}
			else
			{
				GenImage1(&img, "byte", w, h, reinterpret_cast<Hlong>(pDisplayFrame->bufPtr()));
			}
			if (_cb)
			{
				_cb(w, h, img, _wnd);
			}
		}
	}
	return img;
}

void CameraManager::SoftwareTrigger()
{
	qDebug() << __FUNCTION__;
	//m_event = event;
	_stream->detachGrabbing(GenICam::IStreamSource::Proc(&CameraManager::onGetFrame, this));
	//执行一次软触发
	Dahua::GenICam::IAcquisitionControlPtr sptrAcquisitionCtl = GenICam::CSystem::getInstance().createAcquisitionControl(_currentCamera);
	if (NULL == sptrAcquisitionCtl.get())
	{
		qDebug() << ("create AcquisitionControl object fail.\n");
		//emit connectStateEvent(CONNECT_FAIL);
		return;
	}
	Dahua::GenICam::CCmdNode cmdNode = sptrAcquisitionCtl->triggerSoftware();
	bool bRet = cmdNode.execute();
	if (!bRet)
	{
		qDebug() << ("Software Trigger is fail.\n");
		//实际应用中应及时释放相关资源，如diconnect相机等，不宜直接return
		return;
	}	
}